﻿<?PHP


class Gallery
{
	const POSITION_CENTER = 1;
	/**
	 * db - БД
	 *
	 * @var DB
	 */
	public $db = null;
	/**
	 * Директория - хранилище галереи
	 *
	 * @var string
	 */
	public $dir = "";
	/**
	 * конструктор
	 *
	 * @param DB $DB
	 * @param array $params
	 */
	function __construct(&$DB,$dir)
	{
		$this->dir = $dir;
		$this->db = &$DB;
	}
	
	public function & GetGalleriesList($startIndex = 0,$cnt = -1)
	{
		$Query = "SELECT * FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_GALS." ORDER BY weight";
		if ( ($startIndex==0) && ($cnt==-1))
		{
			//all
			$Result = $this->db->getAll($Query,array(),DB_FETCHMODE_ASSOC);
			if (PEAR::isError($Result))
				throw new fwException($Result->getMessage(),$Result->getCode());
			
			return $Result;
		}
		else
		{
			$Result = $this->db->limitQuery($Query,$startIndex,$cnt);
			if (PEAR::isError($Result))
				throw new fwException($Result->getMessage(),$Result->getCode());
			
			While ($row=$Result->fetchRow(DB_FETCHMODE_ASSOC))
				$rows[]=$row;
			return $rows;
		}
		return false;
	}
	public function GetGalleriesCount()
	{
		$Result = $this->db->getOne("SELECT COUNT(*) FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_GALS);
		if (PEAR::isError($Result)) throw new fwException($Result->getMessage(),$Result->getCode());
		return $Result;	
	}
	public function AddGallery($params)
	{
		$str_1 = implode(',', array_keys($params));
		$str_2 = implode("','", array_values($params));
		
		$str_1 = "INSERT INTO ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_GALS."( ".$str_1.") VALUES('".$str_2."')";
		
		$Result = $this->db->query($str_1);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(),$Result->getCode());
		$Result = $this->db->getOne("SELECT LAST_INSERT_ID()");
		return $Result;
	}
	public function GetGallery($id)
	{
		$Result = $this->db->getAll("SELECT * FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_GALS." WHERE id=".$id." LIMIT 0,1",array(),DB_FETCHMODE_ASSOC);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(), $Result->getCode());
		return $Result[0];
	}
	public function SetGallery($id,$params)
	{
		foreach ($params as $key => $value) {
			$field[] = $key."='".$value."'";
		}
		
		$str = implode(' , ',$field);
		$Query = "UPDATE ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_GALS." SET ".$str." WHERE id=".$id;
		
		$Result = $this->db->query($Query);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(),$Result->getCode());
	}
	/** Добавляет новую картинку в галерею
	 * @param $id - идентификатор галереи
	 * @param $params - параметры картинки
	 * @return int идентификатор новой записи в галареи
	 */
	public function AddGalleryItem($id,$params)
	{
		$params['gal_id'] = $id;
		$str_1 = implode(',', array_keys($params));
		$str_2 = implode("','", array_values($params));
				
		$str_1 = "INSERT INTO ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_ITEMS."( ".$str_1.") VALUES('".$str_2."')";
		$Result = $this->db->query($str_1);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(),$Result->getCode());
		$Result = $this->db->getOne("SELECT LAST_INSERT_ID()");
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(),$Result->getCode());
		return $Result;
	}
	/**
	 * Закачивает изображение, именует его с идентификаторов $id
	 * и префиксом $name_prefix
	 * 
	 * Если такой файл уже существует - перезаписывает его.
	 * Записывает в базу данных размеры изображения
	 * 
	 * Накладывает водяной знак, если задан путь к файлу маски
	 * 
	 * Если в процессе закачивания произошли ошибки, то возникают исключения
	 *
	 * @param int $id - идентификатор картинки, должен уже существовать в базе
	 * @param string $fileFieldName - название поля в форме
	 * @param string $name_prefix - префикс для имени файла
	 * @param string $watermark_file - водяной знак, если null, то водяной хнак не накладывается
	 */
	public function UploadItem($id,$fileFieldName,$name_prefix,$watermark_file=null)
	{
		$this->_checkUploadingProcess($fileFieldName);
		
		list($functpostfix,$ext) = $this->_CheckFileFormat($_FILES[$fileFieldName]['name']);
		
		$p['ext'] = $ext;
		$filename = $this->dir.$name_prefix.$id.'.'.$ext;
		
		$create_funct = 'imagecreatefrom'.$functpostfix;
		$out_funct = 'image'.$functpostfix;
		
		if (move_uploaded_file($_FILES[$fileFieldName]['tmp_name'], $filename))
		{
			list($width, $height) = getimagesize($filename);
			$p[$name_prefix.'w'] = $width;
			$p[$name_prefix.'h'] = $height;
			
			if ($watermark_file!=null)
			{
				$im = $create_funct($filename);
				$this->_AddWatermark($im,$watermark_file);
				$out_funct($im,$filename);
				imagedestroy($im);
			}
			$this->SetGalleryItem($id,$p);
		}
		else throw new FileSystemException("Во время перемещения закаченного файла произошла ошибка",0);
	}
	/**
	 * Проверка процесса загрузки
	 * Если процесс загрузки происходит с ошибками 
	 * Возникают исключения.
	 *
	 * @param string $fileFieldName - название поля в форме закачки файла
	 * @return void
	 */
	private function _checkUploadingProcess($fileFieldName)
	{
		if (!isset($_FILES[$fileFieldName])) throw new fwException('Файл не загружен: не установлена переменная $_FILES["'.$fileFieldName.'"]',0);
		if (isset($_FILES[$fileFieldName]['error']))
		{
			switch ($_FILES[$fileFieldName]['error'])
			{
				case UPLOAD_ERR_INI_SIZE:
				case UPLOAD_ERR_FORM_SIZE:
					throw new UploadingFileProcessException('Превышен максимальный размер файла',$_FILES[$fileFieldName]['error']);
					break;
				case UPLOAD_ERR_PARTIAL:
					throw new UploadingFileProcessException('Загрузка файла была прервана',$_FILES[$fileFieldName]['error']);
					break;
				case UPLOAD_ERR_NO_TMP_DIR:
					throw new UploadingFileProcessException('Не задана временная директория на сервере',$_FILES[$fileFieldName]['error']);
					break;
				case UPLOAD_ERR_CANT_WRITE:
					throw new UploadingFileProcessException('Файл не может быть записан на диск',$_FILES[$fileFieldName]['error']);
					break;
				case UPLOAD_ERR_NO_FILE:
					throw new UploadingFileProcessException('Файл для закачки не был задан',$_FILES[$fileFieldName]['error']);
					break;
			}
		}
		else
		{
			throw new RequestVariableNotSetException('Файл не загружен: не установлена переменная $_FILES["'.$fileFieldName.'"]["error"]',0);
		}
		if (!is_uploaded_file($_FILES[$fileFieldName]['tmp_name'])) throw new UploadingFileProcessException("Файл не загружен",0);
	}
	/**
	 * Проверка формата файла изображения
	 * 
	 * Вызывает исключение FileFormatNotSupportedException, если файл имеет неверный формат
	 * 
	 * Возврщает массив:
	 * [0] string - постфикс для графических функций пакета GD, если формат поддерживается.
	 * [1] string - расширение файла
	 *
	 * @param string $filename - имя файла
	 * @return array см описание метода
	 */
	private function _CheckFileFormat($filename)
	{
		$ext = substr($filename,strrpos($filename, ".")+1);
		$ext = strtolower($ext);
		
		if (($ext!="jpg")  &&  ($ext!="gif")  &&  ($ext!="png")  &&  ($ext!="jpeg")) throw new FileFormatNotSupportedException("Данный формат изображения ($ext) не поддерживается",0);
		if ($ext=="jpg") $functpostfix = 'jpeg'; else $functpostfix = $ext;
		return array($functpostfix,$ext);
	}
	/**
	 * Загружает новую картинку в галерею
	 * Изображение добавляется в базу, создаются уменьшенные пропорциональные копии изображения 
	 * в соответствии с заданными размерами.
	 * Если задана маска, тогда накладывается маска.
	 * Если заданная маска больше чем картинка, маска будет масштабирована
	 * 
	 * $sizes - массив:
	 * ['small'][0] - ширина малой картинки
	 * ['small'][1] - высота малой картинки
	 * ['small'][2] - префикс для имени файла
	 * ['medium'] - аналогично
	 * ['native'] - аналогично
	 * 
	 * $watermark - массив:
	 * ['small'][0] - имя файла маски для маленькой картинки
	 * ['small'][1] - позиция маски
	 * ['medium'] - аналогично
	 * ['native'] - аналогично
	 *
	 * @param int $id - идентификатор галереи, в которую будет добавлена картинка
	 * @param string $fileFieldName - название поля формы, тип которой "FILE INPUT"
	 * @param mixed array $params - параметры для вставки в базу данных (имена соответствуют полям таблицы)
	 * @param mixed array $sizes - массив размеров
	 * @param mixed array $watermark - массив масок для разных копий картинки
	 * @return int или boolean идентификатор добавленной картинки или false если ошибка
	 */
	public function UploadGalleryItem($id,$fileFieldName,$params,$sizes,$watermark=null)
	{
		$this->_checkUploadingProcess($fileFieldName);		
		list($functpostfix,$ext) = $this->_CheckFileFormat($_FILES[$fileFieldName]['name']);
		
		$params['ext'] = $ext;
		$item_id = $this->AddGalleryItem($id,$params);
		$filename = $this->dir.$item_id.'.'.$ext;
		$create_funct = 'imagecreatefrom'.$functpostfix;
		$out_funct = 'image'.$functpostfix;
		
		if (move_uploaded_file($_FILES[$fileFieldName]['tmp_name'], $filename))
		{
			chmod($filename, 0644);
			list($width, $height) = getimagesize($filename);
			$p = array();
			//Для каждого заданного размера
			foreach ($sizes as $thumb_type => $size){
				if (count($size)>2){
					$k = min($size[0]/$width,$size[1]/$height);
					
					$new_width = ($k<1) ? $k*$width : $width;
					$new_height = ($k<1) ? $k*$height : $height;				
					
					$source = $create_funct($filename);
					$thumb = $this->_imageCopyResizedImage($source,$width,$height,$new_width,$new_height,$functpostfix);
					if (isset($watermark[$thumb_type][0])) 
					{
						$thumb=$this->_AddWatermark($thumb,$watermark[$thumb_type][0],$watermark[$thumb_type][1]);
						$out_funct($thumb,$this->dir.$size[2].$item_id.'.'.$ext,100);
					}
					else $out_funct($thumb,$this->dir.$size[2].$item_id.'.'.$ext,100);
					imagedestroy($thumb);
					
					$p[$size[2].'w'] = $new_width;
					$p[$size[2].'h'] = $new_height;
				}
				else
				{
					$p['w'] = $width;
					$p['h'] = $height;
				}
			}
			
			$this->SetGalleryItem($item_id,$p);
			return $item_id;
		}
		else throw new FileSystemException("Во время перемещения закаченного файла произошла ошибка",0);
		return false;
	}
	public function SetGalleryItem($id,$params)
	{
		foreach ($params as $key => $value) {
			$field[] = $key."='".$value."'";
		}
		
		$str = implode(' , ',$field);
		$Query = "UPDATE ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_ITEMS." SET ".$str." WHERE id=".$id;
		
		$Result = $this->db->query($Query);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(),$Result->getCode());
	}
	public function GetGalleryItem($id)
	{
		$Result = $this->db->getAll("SELECT * FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_ITEMS." WHERE id=".$id." LIMIT 0,1",array(),DB_FETCHMODE_ASSOC);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(), $Result->getCode());
		return $Result[0];
	}
	public function GetGalleryTopItem($id)
	{
		$Result = $this->db->getAll("SELECT * FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_ITEMS." WHERE gal_id=".$id." ORDER BY weight DESC LIMIT 0,1",array(),DB_FETCHMODE_ASSOC);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(), $Result->getCode());
		return $Result[0];
	}
	public function GetGalleryItemsCount($id)
	{
		$Result = $this->db->getOne("SELECT COUNT(*) FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_ITEMS." WHERE gal_id = {$id}");
		if (PEAR::isError($Result)) throw new fwException($Result->getMessage(),$Result->getCode());
		return $Result;	
	}
	public function &GetGalleryItemsList($id,$startIndex = 0,$cnt = -1)
	{
		$Query = "SELECT * FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_ITEMS." WHERE gal_id={$id} ORDER BY weight ";
		if ( ($startIndex==0) && ($cnt==-1))
		{
			//all
			$Result = $this->db->getAll($Query,array(),DB_FETCHMODE_ASSOC);
			if (PEAR::isError($Result))
				throw new fwException($Result->getMessage(),$Result->getCode());
			return $Result;
		}
		else
		{
			$Result = $this->db->limitQuery($Query,$startIndex,$cnt);
			if (PEAR::isError($Result))
				throw new fwException($Result->getMessage(),$Result->getCode());
			
			While ($row=$Result->fetchRow(DB_FETCHMODE_ASSOC))
				$rows[]=$row;
			return $rows;
		}
		return false;
	}
	public function DeleteGallery($id)
	{
		$list = $this->GetGalleryItemsList($id);
		foreach ($list as $item) {
			$this->DeleteItem($item['id']);
		}
		$Result = $this->db->query("DELETE FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_GALS." WHERE id=".$id);
	}
	/**
	 * Удаление изображения и его вариантов из галереи
	 *
	 * @param int $id - идентификатор изображения
	 * @param array $prefixes - массив префиксов
	 */
	public function DeleteItem($id, $prefixes)
	{
		$item = $this->GetGalleryItem($id);
	
		$Result = $this->db->query("DELETE FROM ".FW_DB_TBL_PREFIX.FW_GALLERY_TBL_ITEMS." WHERE id=".$id);
		if (PEAR::isError($Result))
			throw new fwException($Result->getMessage(),$Result->getCode());
			
		$raiseException = false;
			
		foreach ($prefixes as $pref) {
			$raiseException = $raiseException | (unlink ($this->dir.$pref.$id.'.'.$item['ext'])===false);
		}
		
		if ($raiseException) throw new FileSystemException("Не все варианты картинки с идентификатором {$id} удалось удалить");
	}
	private function _imageCopyResizedImage($src,$src_w,$src_h,$dst_w,$dst_h)
	{
		$thumb = imagecreatetruecolor($dst_w,$dst_h);
		//$out_funct = 'image'.$functpostfix;
		//imagecopyresized($thumb, $src, 0, 0, 0, 0, $dst_w, $dst_h, $src_w, $src_h);
		//imageinterlace($thumb,1);
		imagecopyresampled($thumb,$src,0,0,0,0,$dst_w,$dst_h,$src_w,$src_h);
		return $thumb;
	}
	private function _imageCopyMerge($mask_filename,$dst,$dst_w,$dst_h,$alpha)
	{
		$im_logo = imagecreatefromgif($mask_filename);
		list($w, $h) = getimagesize($mask_filename);
		imagecopymerge ($dst, $im_logo, $dst_w-$w, $dst_h-$h, 0, 0, $w, $h, $alpha);
	}
	/**
	 * Добавляет водяной знак на картинку
	 *
	 * @param image $dst_im - исходное изображение
	 * @param string $water_mark_filename - имя файла маски с водяным знаком
	 * @param int $position - позиция маски: Gallery::POSITION_CENTER - по центру
	 */
	private function _AddWatermark($dst_im,$water_mark_filename,$position=Gallery::POSITION_CENTER)
	{
		if (!file_exists($water_mark_filename))
			throw new fwException("Ресурс не найден ".$water_mark_filename,-1);
		$mask = imagecreatefrompng($water_mark_filename);
		
		$im_w = imagesx($dst_im);
		$im_h = imagesy($dst_im);
		
		$wm_w = imagesx($mask);
		$wm_h = imagesy($mask);
		
		$new_mask = null;
		$wm_new_w = $wm_new_h = 0;
	
		if (($wm_w>=$im_w) || ($wm_h>=$im_h))
		{
			$wm_new_w = $im_w*0.9;
			$wm_new_h = $im_h*0.9;
			$k = $wm_new_w/$wm_w;
			$_k = $wm_new_h/$wm_h;
		
			$k = $k<$_k? $k : $_k;
		
			$wm_new_w = (int)($wm_w*$k);
			$wm_new_h = (int)($wm_h*$k);
		
			$new_mask = imagecreatetruecolor($wm_new_w,$wm_new_h);
			imagealphablending($new_mask, false);
			imagecopyresampled($new_mask,$mask,0,0,0,0,$wm_new_w,$wm_new_h,$wm_w,$wm_h);
			imageAlphaBlending($new_mask, true);
			imageSaveAlpha($new_mask, true);
		}
		else
		{
			$new_mask = $mask;
			$wm_new_w = $wm_w;
			$wm_new_h = $wm_h;
		}

		$pos = array();		
		switch($position)
		{
			case Gallery::POSITION_CENTER:
				$pos[0] = (int) ($im_w-$wm_new_w)/2;
				$pos[1] = (int) ($im_h-$wm_new_h)/2;
				break;
			default:
				$pos = array(0,0);
				break;
		}
		imagecopyresampled($dst_im,$new_mask,$pos[0],$pos[1],0,0,$wm_new_w,$wm_new_h,$wm_new_w,$wm_new_h);
		imageAlphaBlending($dst_im, true);
		
		//header("Content-type: image/jpeg");
		//imageSaveAlpha($dst_im, true);
		//imagejpeg($dst_im,null,100);
		//exit;
		return $dst_im;
	}
	public function ScaleImage($openFile,$saveAsFile, $newWidth, $newHeight)
	{
		list($postfix1) = $this->_CheckFileFormat($openFile);
		list($postfix2) = $this->_CheckFileFormat($saveAsFile);
		
		$create_funct = 'imagecreatefrom'.$postfix1;
		$out_funct = 'image'.$postfix2;
		
		$source = $create_funct($openFile);
		list($w, $h) = getimagesize($openFile);
		$thumb = $this->_imageCopyResizedImage($source,$w,$h,$newWidth, $newHeight);
		$out_funct($thumb,$saveAsFile,100);
	}
	public function CropImage($openFile,$saveAsFile, $src_x, $src_y, $dst_w, $dst_h)
	{
		list($postfix1) = $this->_CheckFileFormat($openFile);
		list($postfix2) = $this->_CheckFileFormat($saveAsFile);
		
		$create_funct = 'imagecreatefrom'.$postfix1;
		$out_funct = 'image'.$postfix2;
		
		$src = $create_funct($openFile);
		list($w, $h) = getimagesize($openFile);
		
		$thumb = imagecreatetruecolor($dst_w,$dst_h);

		//imagecopyresized($thumb, $src, 0, 0, $src_x, $src_y, $dst_w, $dst_h, $dst_w, $dst_h);
		imagecopyresampled($thumb,$src,0,0,$src_x, $src_y,$dst_w,$dst_h,$dst_w, $dst_h);
		
		$out_funct($thumb,$saveAsFile,100);
	}
}

?>